package org.ix.shiro.shiro;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import org.ix.common.models.IxUser;
import org.ix.shiro.service.AccountService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.ix.shiro.service.JwtService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Set;

@Component
public class IxAuthorizingRealm extends AuthorizingRealm {

    final AccountService accountService;
    final JwtService jwtService;

    @Autowired
    public IxAuthorizingRealm(AccountService accountService, JwtService jwtService) {
        this.accountService = accountService;
        this.jwtService = jwtService;
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof IxAuthenticationToken;
    }

    /**
     * 认证(登录时调用)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String accessToken = ((IxAuthenticationToken) token).getPrincipal();
        if (StringUtils.isBlank(accessToken)) {
            throw new IllegalStateException("用户未登录");
        }
        Claims claims;
        try {
            claims = jwtService.parseToken(accessToken);
        } catch (ExpiredJwtException e) {
            throw new ExpiredCredentialsException("token过期, 请重新登录");
        }
        IxUser user = accountService.getUser(claims.getSubject());
        if (user == null) {
            throw new IncorrectCredentialsException("token失效，请重新登录");
        }
        return new SimpleAuthenticationInfo(user, accessToken, getName());
    }

    /**
     * 授权(验证权限时调用)
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        IxUser user = (IxUser) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Set<String> roles = accountService.getUserRoles(user.getId());
        info.setRoles(roles);
        info.setStringPermissions(accountService.getUserPermissions(roles));
        return info;
    }
}
